package apportioner

import (
	// "bp/cache"
	sqlc "bp/db/sqlc"
	"bp/internal/nsqserver/producer"
	offApportionment "bp/internal/service/entity/off_apportionment"
	// "encoding/json"
	"fmt"

	// offTransaction "bp/internal/service/entity/off_transaction"
	offTrial "bp/internal/service/entity/off_trial"

	// "bp/internal/service/entity/promotion"
	// "bp/internal/service/param"
	// "bp/internal/service/com/offer"
	"bp/internal/util"
	"context"
)

// type ApportionOfOrderDetail struct {
// 	OutTransNo           string `json:"out_trans_no"`
// 	OutOrderNo           string `json:"out_order_no"`
// 	OutAfterSaleNo       string `json:"out_after_sale_no"`
// 	OutOrderDetailID     int64  `json:"out_order_detail_id"`
// 	OutAfterSaleDetailID int64  `json:"out_after_sale_detail_id"`
// 	Off                  int32  `json:"off"`
// 	Cnt                  int32  `json:"cnt"`
// }

type AggValue struct {
	Off int32 // 累加聚合(a+b)
	Cnt int32 // 条件累加/取大值(a+b>m?max(a,b):a+b)
}

// apportionOff 分摊优惠
func (s *ApportionerComServiceImp) apportionOff(ctx context.Context, q *sqlc.Queries, offTransactionPtr *sqlc.OffTransaction) (apportionmentOfOrderDetailPtrs []*producer.ApportionmentOfOrderDetail, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	transactionID := offTransactionPtr.ID

	upsertOffApportionmentParamsPtrs, err := s.genUpsertOffApportionmentParamsPtrs(ctx, q, offTransactionPtr)
	if err != nil {
		return
	}
	slog.Infof("交易(%d)的生成优惠分摊upert参数:(%d) ok", transactionID, len(upsertOffApportionmentParamsPtrs))
	offApportionmentPtrs, err := s.entityHub.OffApportionmentService.RefreshOffApportionmentsByTransactionID(ctx, q,
		&offApportionment.RefreshOffApportionmentsByTransactionIDParam{
			TransactionID:                    transactionID,
			UpsertOffApportionmentParamsPtrs: upsertOffApportionmentParamsPtrs,
		})
	if err != nil {
		return
	}
	slog.Infof("获得交易(%d)的分摊明细 数量:(%d) ok", transactionID, len(offApportionmentPtrs))

	vals := util.MapReduceString(util.ToGenericSlice(offApportionmentPtrs), func(i interface{}) string {
		v := i.(*sqlc.OffApportionment)
		return fmt.Sprintf("%d-%d-%d", v.TransactionID, v.OutOrderDetailID, v.OutAfterSaleDetailID)
	}, func(i interface{}) interface{} {
		v := i.(*sqlc.OffApportionment)
		return &producer.ApportionmentOfOrderDetail{
			OutTransNo:           v.OutTransNo,
			OutOrderNo:           v.OutOrderNo,
			OutAfterSaleNo:       v.OutAfterSaleNo,
			OutOrderDetailID:     v.OutOrderDetailID,
			OutAfterSaleDetailID: v.OutAfterSaleDetailID,
		}
	}, func(i1 interface{}, i2 interface{}) interface{} {
		agg := i1.(*AggValue)
		v2 := i2.(*sqlc.OffApportionment)
		tmpCnt := agg.Cnt + v2.Cnt
		// bv2, _ := json.Marshal(v2)
		// slog.Infof("v2=>%s", string(bv2))
		agg.Off += v2.Off
		agg.Cnt = util.Int32IfThenElse(tmpCnt > v2.OutOrderDetailCnt, util.Int32IfThenElse(agg.Cnt > v2.Cnt, agg.Cnt, v2.Cnt), tmpCnt)
		return agg
	}, func(ro *util.ReducedObject) interface{} {
		v := ro.G.(*producer.ApportionmentOfOrderDetail)
		agg := ro.A.(*AggValue)
		// bv1, _ := json.Marshal(v)
		// bv2, _ := json.Marshal(agg)
		// slog.Infof("v=>%s", string(bv1))
		// slog.Infof("agg=>%s", string(bv2))
		v.Off = agg.Off
		v.Cnt = agg.Cnt
		return v
	}, func() interface{} {
		return &AggValue{}
	})
	slog.Infof("交易(%d)按分摊明细聚合 数量:(%s) ok", transactionID, len(vals))

	var updateOffTransactionDetailParamPtrs []*sqlc.UpdateOffTransactionDetailOffAndCntByTransactionIDAndDetailIDParams
	for _, val := range vals {
		ptr := val.(*producer.ApportionmentOfOrderDetail)
		apportionmentOfOrderDetailPtrs = append(apportionmentOfOrderDetailPtrs, ptr)
		updateOffTransactionDetailParamPtrs = append(updateOffTransactionDetailParamPtrs, &sqlc.UpdateOffTransactionDetailOffAndCntByTransactionIDAndDetailIDParams{
			TransactionID:        transactionID,
			OutOrderDetailID:     ptr.OutOrderDetailID,
			OutAfterSaleDetailID: ptr.OutAfterSaleDetailID,
			Off:                  ptr.Off,
			Cnt:                  ptr.Cnt,
		})
	}

	err = s.entityHub.OffTransactionService.BatchUpdateOffTransactionDetailOffAndCnt(ctx, q, updateOffTransactionDetailParamPtrs)
	if err != nil {
		return
	}
	slog.Infof("交易(%d)批量更新交易明细 ok", transactionID)

	err = s.entityHub.OffTransactionService.MarkOffTransactionApportioned(ctx, q, transactionID)
	if err != nil {
		return
	}
	slog.Infof("交易(%d)标记已分摊 ok", transactionID)

	slog.Infof("交易(%d)ApportionOff detail(%s) ok", transactionID, len(apportionmentOfOrderDetailPtrs))
	return
}

func (s *ApportionerComServiceImp) genUpsertOffApportionmentParamsPtrs(ctx context.Context, q *sqlc.Queries,
	offTransactionPtr *sqlc.OffTransaction) (
	upsertOffApportionmentParamsPtrs []*sqlc.UpsertOffApportionmentParams,
	err error) {
	transactionID := offTransactionPtr.ID
	offTrialPtrs, err := s.entityHub.OffTrialService.ListOffTrialPtrs(ctx, q, &offTrial.ListOffTrialPtrsParam{
		OutTransNo: offTransactionPtr.OutTransNo,
		TrialScene: offTransactionPtr.TransactScene,
	})
	if err != nil {
		return
	}
	if len(offTrialPtrs) == 0 {
		return
	}
	offTrialItemPtrs, err := s.entityHub.OffTrialService.ListOffTrialItemPtrs(ctx, q, &offTrial.ListOffTrialItemPtrsParam{
		OutTransNo: offTransactionPtr.OutTransNo,
		TrialScene: offTransactionPtr.TransactScene,
	})
	if err != nil {
		return
	}
	offTransactionDetailPtrs, err := s.entityHub.OffTransactionService.ListOffTransactionDetailPtrsByTransactionID(ctx, q, transactionID)
	if err != nil {
		return
	}
	// 这里要解决试算明细和交易明细detailID没有直接对应,需要用owner_id+item_id+item_spec_id来对应
	theMapOfOffTransactionDetail := s.ConvOffTrialItemMapToOffTransactionDetail(offTrialItemPtrs, offTransactionDetailPtrs,
		s.ExtractOwnerOffTrialItemKey(offTransactionPtr.OwnerID),
		func(otd *sqlc.OffTransactionDetail, k OffCompareKey) bool {
			return k == s.ExtractOwnerOffTransactionDetailKey()(otd)
		})
	// 目前可以判定(off_type=limit是单品类优惠||off_item_type=activity&&off_type=discount限时折扣)不用分摊,其他都是多品类需要分摊
	// 生成单品优惠分摊
	offTrialPtrsOfSingle, offTrialPtrsOfNonSingle := s.entityHub.OffTrialService.SplitOffTrialPtrs(offTrialPtrs, func(ot *sqlc.OffTrial) bool {
		return s.entityHub.OffTrialService.IsItemOff(ot)
	})
	upsertOffApportionmentParamsPtrs = append(upsertOffApportionmentParamsPtrs,
		s.genUpsertOffApportionmentParamsPtrsOfSingle(offTransactionPtr, theMapOfOffTransactionDetail, offTrialPtrsOfSingle, offTrialItemPtrs)...)

	// 生成多品优惠分摊
	offTrialPtrsOfMultiple, offTrialPtrsOfNonSingleAndMultiple := s.entityHub.OffTrialService.SplitOffTrialPtrs(offTrialPtrsOfNonSingle, func(ot *sqlc.OffTrial) bool {
		return s.entityHub.OffTrialService.IsItemsOff(ot)
	})
	upsertOffApportionmentParamsPtrs = append(upsertOffApportionmentParamsPtrs,
		s.genUpsertOffApportionmentParamsPtrsOfMultiple(offTransactionPtr, theMapOfOffTransactionDetail, offTrialPtrsOfMultiple, offTrialItemPtrs)...)

	theMapOfOffDistribution := s.genItemOffDistributionByUpsertOffApportionmentParamsPtrs(upsertOffApportionmentParamsPtrs)
	// 整单里的卡折扣

	offTrialPtrsOfCardDiscountOverall, _ := s.entityHub.OffTrialService.SplitOffTrialPtrs(offTrialPtrsOfNonSingleAndMultiple, func(ot *sqlc.OffTrial) bool {
		return s.entityHub.OffTrialService.IsOverallOff(ot)
	})
	upsertOffApportionmentParamsPtrs = append(upsertOffApportionmentParamsPtrs,
		s.genUpsertOffApportionmentParamsPtrsOfOverall(offTransactionPtr, theMapOfOffTransactionDetail, theMapOfOffDistribution, offTrialPtrsOfCardDiscountOverall, offTransactionDetailPtrs)...)
	return
}
